home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d7 / commdrvr.arc / TIRS232.ASM < prev    next >
Assembly Source File  |  1988-04-11  |  29KB  |  780 lines

  1.     page    60,132
  2. ;***********************************************************
  3. ;**                                                       **
  4. ;**  Device Driver for RS232 communications               **
  5. ;**  TI PC Version                                        **
  6. ;**  Copyright (C) Texas Instruments 1986                 **
  7. ;**  Author: Greg Haley                                   **
  8. ;**                                                       **
  9. ;**  THIS SOURCE CODE MAY BE DISTRIBUTED AND MODIFIED     **
  10. ;**  ONLY IF THE ORIGINAL COPYRIGHT AND AUTHOR CREDITS    **
  11. ;**  REMAIN INTACT.                                       **
  12. ;**                                                       **
  13. ;**  Project Start Date: 11/20/86                         **
  14. ;**                                                       **
  15. ;**  RE: 12/29/86 by Greg Haley                           **
  16. ;**    Added send_xon routine.                            **
  17. ;**    Added TI internal modem support.                   **
  18. ;**    Added 19200 baud.                                  **
  19. ;**                                                       **
  20. ;***********************************************************
  21.  
  22.         name    tirs232 
  23.         title   Device Driver for TI PC Communications  
  24.  
  25. code    segment byte
  26.    assume cs:code,ds:nothing,es:nothing
  27.  
  28.     include    rs232.inc
  29.  
  30.     page
  31. ;***********************************************************
  32. ;**  Keyboard Routines                                    **
  33. ;***********************************************************
  34. keyboard equ    4ah            ; TI PC keyboard INT
  35. altah    db    0            ; Storage for high byte of key input
  36.  
  37. k_ready:
  38.     mov    al,cs:altah        ; Get 2nd half of F-key?
  39.     or    al,al
  40.     jnz    k_rdy_xit        ; Yes, skip to end
  41.  
  42.         mov     ah,1                    ; Is a char waiting?
  43.         int     keyboard
  44.     jz    k_rdy_xit        ; No, exit
  45.  
  46.     or    ax,ax            ; If it was a ^C, remove it
  47.     jnz    k_rdy_xit
  48.     xor    ah,ah
  49.     int    keyboard
  50.     jmp    short k_ready        ; And try again
  51.  
  52. k_rdy_xit:
  53.     ret
  54.  
  55. k_read:
  56.     xor    ax,ax            ; Clear AX
  57.  
  58.     xchg    al,cs:altah        ; Get 2nd half of F-key?
  59.     or    al,al
  60.     jnz    k_r_xit            ; Yes, skip to end
  61.  
  62. k_r_1:
  63.         xor     ah,ah
  64.         int     keyboard
  65.     
  66.     or    ax,ax            ; Was it a ^C?
  67.     jz    k_r_1            ; Yes, get another
  68.  
  69.     or    al,al            ; Is it a F-key?
  70.     jnz    k_r_xit            ; No, exit
  71.     mov    cs:altah,ah        ; Yes, save 2nd half
  72.  
  73. k_r_xit:
  74.     ret
  75.  
  76.     page
  77. ;***********************************************************
  78. ;**  Communications Routines                              **
  79. ;***********************************************************
  80. recv_size       equ     800h            ; Receive buffer size
  81.                     ; Must be one of these values:
  82.                     ; 0004h    = 4 bytes
  83.                     ; 0008h    = 8 bytes
  84.                     ; 0010h    = 16 bytes
  85.                     ; 0020h    = 32 bytes
  86.                     ; 0040h    = 64 bytes
  87.                     ; 0080h    = 128 bytes
  88.                     ; 0100h    = 256 bytes
  89.                     ; 0200h    = 512 bytes
  90.                     ; 0400h    = 1024 bytes
  91.                     ; 0800h    = 2048 bytes
  92.                     ; 1000h    = 4096 bytes
  93.                     ; 2000h    = 8192 bytes
  94.                     ; 4000h    = 16384 bytes
  95.                     ; 8000h    = 32768 bytes
  96. recv_limit      equ     not recv_size   ; Receive buffer limit mask
  97. busy_len        equ     recv_size *3 /4 ; Go busy at 3/4 buf length
  98. not_busy_len    equ     recv_size /2    ; Not busy at 1/2 buf length
  99.  
  100. int_controller  equ     19h             ; 8259A Interrupt Controller port
  101. int_ack         equ     18h             ; 8259A Interrupt Acknowledge port
  102. EOI             equ     00100000b       ; Non-specific EOI
  103.  
  104. enable_ints     equ     01000000b       ; Enable interrupts
  105. disable_ints    equ     11000000b       ; Disable interrupts
  106. dtr_bit         equ     1               ; DTR bit in uart control register
  107. rts_bit         equ     2               ; DTR bit in uart control register
  108. dcd_bit         equ     1               ; DCD bit in modem status register
  109. cts_bit         equ     2               ; CTS bit in modem status register
  110. dsr_bit         equ     4               ; DSR bit in modem status register
  111. scf_bit         equ     8               ; SCF bit in modem status register
  112. ri_bit          equ     16              ; RI  bit in modem status register
  113.  
  114. xon             equ     11h             ; xmit on busy char
  115. xoff            equ     13h             ; xmit off busy char
  116.  
  117.     page
  118. ;***********************************************************
  119. ;**     Variables                                         **
  120. ;***********************************************************
  121.  
  122. old_ss  dw      0                       ; Old SS reg
  123. old_sp  dw      0                       ; Old SP reg
  124.         db      80 dup (?)              ; Stack
  125. i_stack label   byte
  126. rq_head dw      0                       ; Receive Queue start 
  127. rq_tail dw      0                       ; Receive Queue stop 
  128. rq_len  dw      0                       ; Current receive Queue length
  129. rqueue  db      recv_size dup (?)       ; Receive queue
  130. oldseg  dw      0                       ; Old segment for int vector
  131. oldoff  dw      0                       ; Old offset for int vector
  132. busy_hand       db      0               ; busy handling type
  133. r_busy  db      0                       ; recv busy flag
  134. t_busy  db      0                       ; xmit busy flag
  135. xmit_busy       db      0               ; xmit busy flag (for ints)
  136. m_stat  db      0                       ; Current modem status
  137. l_stat  db      0                       ; Current line status
  138. dcw     dw      1100000001010000b       ; default 2400, 8, N, 1
  139. parity_on       db      0               ; Parity flag
  140. ti_modem    db    0        ; Flag for TI internal modem
  141.  
  142. opn_tbl:
  143.         db      0                       ; Needs leading 0 for sync
  144.         db      9                       ; select reg 9
  145.         db      01001001b               ; Reset chan B, MIE, & VIS
  146.         db      12                      ; select reg 12
  147. baudl   db      30                      ; Low byte of baud rate (2400)
  148.         db      13                      ; select reg 13
  149. baudh   db      0                       ; High byte of baud rate
  150.         db      2                       ; select reg 2
  151.         db      0                       ; int vector on
  152.         db      11                      ; select reg 11
  153.         db      01010010b               ; brate generator
  154.         db      14                      ; select reg 14
  155.         db      00000011b               ; enable brate gen.
  156.         db      4                       ; select reg 4
  157. par_stp db      01000100b               ; No parity, 1 stop bit
  158.         db      3                       ; select reg 3
  159. recv_b  db      11000001b               ; recv enable, 8 bits
  160.         db      5                       ; select reg 5
  161. xmit_b  db      11101010b               ; xmit enable, DTR, 8 bits
  162.         db      10                      ; select reg 10
  163.         db      0                       ; NRZ, flags
  164.         db      15                      ; select reg 15
  165.         db      00101000b               ; CTS, DCD int enable
  166.         db      1                       ; select reg 1
  167.         db      00010111b               ; int enable
  168. opn_size        equ     $-opn_tbl
  169.  
  170. opn2_tbl:
  171.         db      0                       ; Sync byte
  172.         db      15                      ; select reg 15
  173.         db      00101000b               ; RI & DSR int enable
  174.         db      1                       ; select reg 1
  175.         db      00000001b               ; external int enable
  176. opn2_size       equ     $-opn2_tbl
  177.  
  178. int_tbl dw      0                       ; Interrupt branch table
  179.         dw      mod_stat
  180.         dw      0
  181.         dw      0
  182.         dw      xmit_mt                  
  183.         dw      mod_stat
  184.         dw      rec_full
  185.         dw      lin_stat
  186.  
  187. ; table for baud rate constants
  188. baud_tbl        dw      696             ; 110
  189.                 dw      510             ; 150
  190.                 dw      254             ; 300
  191.                 dw      126             ; 600
  192.                 dw      62              ; 1200
  193.                 dw      30              ; 2400
  194.                 dw      14              ; 4800
  195.                 dw      6               ; 9600
  196.  
  197. ; table for port number init tables
  198. p_table dw      port1_tbl
  199.         dw      port2_tbl
  200.         dw      port3_tbl
  201.         dw      port4_tbl
  202.  
  203. port_n  dw      port1_tbl               ; default port is 1
  204.  
  205. ; port 1 init table
  206. port1_tbl       dw      40h             ; Interrupt vector for irq
  207.                 db      11111110b       ; Mask to enable irq
  208.                 db      00000001b       ; Mask to unable irq
  209.                 dw      0e7h            ; Receive buffer port
  210.                 dw      0e7h            ; Transmit buffer port
  211.                 dw      0e6h            ;  8530 UART Control port
  212.                 dw      0e6h            ;  8530 UART Status port
  213.                 dw      0e4h            ;  8530 Modem Status port
  214.                 dw      0e6h            ;  8530 interrupt enable register
  215.                 dw      0e0h            ;  8530 interrupt ack register
  216. p_tbl_size      equ     $-port1_tbl
  217.  
  218. ; port 2 init table
  219. port2_tbl       dw      41h             ; Interrupt vector for irq
  220.                 db      11111101b       ; Mask to enable irq
  221.                 db      00000010b       ; Mask to unable irq
  222.                 dw      0efh            ; Receive buffer port
  223.                 dw      0efh            ; Transmit buffer port
  224.                 dw      0eeh            ;  8530 UART Control port
  225.                 dw      0eeh            ;  8530 UART Status port
  226.                 dw      0ech            ;  8530 Modem Status port
  227.                 dw      0eeh            ;  8530 interrupt enable register
  228.                 dw      0e8h            ;  8530 interrupt ack register
  229.  
  230. ; port 3 init table
  231. port3_tbl       dw      42h             ; Interrupt vector for irq
  232.                 db      11111011b       ; Mask to enable irq
  233.                 db      00000100b       ; Mask to unable irq
  234.                 dw      0f7h            ; Receive buffer port
  235.                 dw      0f7h            ; Transmit buffer port
  236.                 dw      0f6h            ;  8530 UART Control port
  237.                 dw      0f6h            ;  8530 UART Status port
  238.                 dw      0f4h            ;  8530 Modem Status port
  239.                 dw      0f6h            ;  8530 interrupt enable register
  240.                 dw      0f0h            ;  8530 interrupt ack register
  241.  
  242. ; port 4 init table
  243. port4_tbl       dw      44h             ; Interrupt vector for irq
  244.                 db      11101111b       ; Mask to enable irq
  245.                 db      00010000b       ; Mask to unable irq
  246.                 dw      0ffh            ; Receive buffer port
  247.                 dw      0ffh            ; Transmit buffer port
  248.                 dw      0feh            ;  8530 UART Control port
  249.                 dw      0feh            ;  8530 UART Status port
  250.                 dw      0fch            ;  8530 Modem Status port
  251.                 dw      0feh            ;  8530 interrupt enable register
  252.                 dw      0f8h            ;  8530 interrupt ack register
  253.  
  254.  
  255. ; defaults for port 1
  256. port_tbl        label   word
  257. comm1_vector    dw      40h             ; Interrupt vector for irq
  258. irq_enab_mask   db      11111110b       ; Mask to enable irq
  259. irq_unab_mask   db      00000001b       ; Mask to unable irq
  260. recv_buffer     dw      0e7h            ; Receive buffer port
  261. send_buffer     dw      0e7h            ; Transmit buffer port
  262. uart_control    dw      0e6h            ;  8530 UART Control port
  263. uart_status     dw      0e6h            ;  8530 UART Status port
  264. modem_status    dw      0e4h            ;  8530 Modem Status port
  265. int_enable      dw      0e6h            ;  8530 interrupt enable register
  266. ack_int         dw      0e0h            ;  8530 interrupt ack register
  267.  
  268.     page
  269. ;***********************************************************
  270. ;**     Subroutine to set up comm chip per the DCW        **
  271. ;**     DCW is in AX                                      **
  272. ;***********************************************************
  273. set_dcw:
  274. ; set parity type
  275.         mov     bl,al                   ; get low byte in BL
  276.         and     bl,00000011b            ; mask unused bits
  277.         and     byte ptr par_stp,11111100b      ; reset parity
  278.         or      byte ptr par_stp,bl     ; change parity
  279.         and     bl,00000001b            ; change parity flag
  280.         mov     byte ptr parity_on,bl   ; 
  281.  
  282. ; set num stop bits
  283.         mov     bl,al                   ; get low byte in BL
  284.         and     bl,00001000b            ; mask unused bits
  285.         or      bl,00000100b            ; 1.5 stop bits not used
  286.         and     byte ptr par_stp,11110011b      ; reset stop bits
  287.         or      byte ptr par_stp,bl     ; change stop bits
  288.         
  289. ; set baud rate
  290.         mov     bl,al                   ; get low byte in BL
  291.         and     bl,01110000b            ; mask unused bits
  292.         mov     cl,3                    ; shift to make word ptr
  293.         shr     bl,cl
  294.         mov     si,offset baud_tbl      ; point to baud table
  295.         xor     bh,bh                   ; make BX a byte ptr
  296.         add     si,bx                   ; SI now points to baud rate const
  297.         mov     dx,word ptr [si]        ; get baud rate in DX
  298.         mov     byte ptr baudl,dl       ; save low byte of baud rate
  299.         mov     byte ptr baudh,dh       ; save high byte of baud rate
  300.  
  301. ; set busy type
  302.         mov     bl,ah
  303.         and     bl,00000011b            ; mask unwanted bits
  304.         mov     byte ptr busy_hand,bl   ; store it
  305.  
  306. ; set port number
  307.         mov     bl,ah                   ; get high byte in BL
  308.         and     bl,00011000b            ; mask unused bits
  309.         shr     bl,1                    ; shift to make word ptr
  310.         shr     bl,1 
  311.         mov     si,offset p_table       ; point to port table
  312.         xor     bh,bh                   ; make BX a byte ptr
  313.         add     si,bx                   ; SI now points to baud rate const
  314.         mov     dx,word ptr [si]        ; get port adrs in DX
  315.         mov     word ptr port_n,dx      ; save port number adrs
  316.  
  317. ; set data bits
  318.         mov     bl,ah                   ; get high byte in BL
  319.         and     bl,01000000b            ; mask unused bits
  320.         or      bl,00100000b            ; make it at least 7 bits
  321.         and     byte ptr xmit_b,10011111b       ; reset xmit data size
  322.         or      byte ptr xmit_b,bl      ; set xmit data size
  323.         shl     bl,1                    ; adjust for recv data size
  324.         and     byte ptr recv_b,00111111b       ; reset recv data size
  325.         or      byte ptr recv_b,bl      ; set recv data size
  326.  
  327. ; Check for internal modem
  328.     mov    ti_modem,al
  329.     and     ti_modem,00000100b    ; TI internal modem if not 0
  330.  
  331.     ret
  332.  
  333.     page
  334. ;***********************************************************
  335. ;**     Subroutine to set up interrupt vector             **
  336. ;**     and initialize the  8530 comm chip                **
  337. ;***********************************************************
  338. init_comm:
  339.         push    ds
  340.         push    cs
  341.         pop     ds
  342.  
  343. ; get correct port parameters
  344.         push    es
  345.         push    cs
  346.         pop     es
  347.  
  348.         mov     si,word ptr port_n      ; get port table adrs
  349.         mov     di,offset port_tbl      ; DI points to table to use
  350.         mov     cx,p_tbl_size           ; CX has table length
  351.         repz    movsb                   ; move it
  352.         
  353.         pop     es
  354.  
  355. ; Save old int vector for irq
  356.         mov     di,comm1_vector
  357.         call    get_vector
  358.         mov     word ptr oldseg,bx
  359.         mov     word ptr oldoff,dx
  360.  
  361. ; Set up int vector for irq
  362.         push    cs                      ; Make BX = CS
  363.         pop     bx
  364.         mov     dx,offset isr
  365.         mov     di,comm1_vector
  366.         call    set_vector
  367.  
  368. ; Enable irq from 8259A
  369.         cli
  370.         in      al,int_controller
  371.         jmp     $+2                     ; delay
  372.         and     al,irq_enab_mask
  373.         out     int_controller,al
  374.         
  375. ; Read receive buffer register
  376.         mov     dx,recv_buffer
  377.         in      al,dx
  378.         
  379. ; Read modem status register
  380.         call    mod_stat
  381.  
  382. ; Read UART status register
  383.         call    lin_stat
  384.  
  385. ; open 8530
  386.         mov     si,offset opn_tbl
  387.         mov     cx,opn_size
  388.         mov     dx,uart_control
  389. init_1:
  390.         lodsb
  391.         out     dx,al
  392.         jmp     $+2                     ; delay
  393.         loop    init_1
  394.  
  395.         mov     si,offset opn2_tbl
  396.         mov     cx,opn2_size
  397.         mov     dx,modem_status
  398. init_2:
  399.         lodsb
  400.         out     dx,al
  401.         jmp     $+2                     ; delay
  402.         loop    init_2
  403.  
  404.         pop     ds
  405.         sti
  406.  
  407. ; Reset TI internal modem if present
  408.     cmp    cs:byte ptr ti_modem,0    ; TI internal modem?
  409.     jz    no_ti_modem        ;  No, exit
  410.     mov    dx,modem_status        ;  Yes, set /RCNTL 
  411.     mov    al,5
  412.     out    dx,al
  413.     mov    al,cs:xmit_b
  414.     or    al,2
  415.     out    dx,al
  416.  
  417. wait_4_ack:
  418.     mov    dx,uart_status         ; Check for ACK
  419.     mov    al,10h
  420.     out    dx,al
  421.         jmp     $+2                     ; delay
  422.         jmp     $+2                     ; delay
  423.     in    al,dx
  424.     test    al,10h            ; Got an ACK?
  425.     jz    wait_4_ack        ;  No, keep looping
  426.  
  427. no_ti_modem:
  428.         ret
  429.  
  430.     page
  431. ;***********************************************************
  432. ;**     Subroutine to restore interrupt vector            **
  433. ;**     and reset the  8530 comm chip                     **
  434. ;***********************************************************
  435. de_init:
  436.         cli
  437.  
  438. ; Disable interrupts on  8530 and drop DTR, RTS
  439.         mov     dx,cs: word ptr int_enable
  440.         mov     al,9                    ; select reg 9
  441.         out     dx,al
  442.         mov     al,disable_ints
  443.         jmp     $+2                     ; delay
  444.         out     dx,al
  445.         jmp     $+2                     ; delay
  446.         jmp     $+2                     ; delay
  447.  
  448. ; Disable irq
  449.         in      al,int_controller
  450.         or      al,cs:byte ptr irq_unab_mask
  451.         jmp     $+2                     ; delay
  452.         jmp     $+2                     ; delay
  453.         out     int_controller,al
  454.  
  455. ; It's probably not a good idea to restore the vector at close in 
  456. ; this case, but here's the code to do it:
  457. ;
  458. ; Restore int vector for irq
  459. ;       mov     bx,cs:word ptr oldseg
  460. ;       mov     dx,cs:word ptr oldoff
  461. ;       mov     di,comm1_vector
  462. ;       call    set_vector
  463.         sti
  464.         ret
  465.  
  466.     page
  467. ;***********************************************************
  468. ;**     Interrupt Service Routine                         **
  469. ;***********************************************************
  470. isr:
  471.         cli
  472.         cld
  473. ; Set up new stack
  474.         mov     cs:word ptr old_sp,sp
  475.         mov     cs:word ptr old_ss,ss
  476.         mov     sp,cs
  477.         mov     ss,sp
  478.         mov     sp,offset i_stack
  479.  
  480.         push    ax
  481.         push    bx
  482.         push    cx
  483.         push    dx
  484.         push    ds
  485.  
  486.         push    cs
  487.         pop     ds
  488.  
  489. ; Verify int came from  8530
  490.         mov     dx,uart_status
  491.         mov     al,3                    ; reg 3
  492.         out     dx,al                   ; select reg 3
  493.         jmp     $+2                     ; delay
  494.         jmp     $+2                     ; delay
  495.         in      al,dx                   ; read reg 3
  496.         or      al,al                   ; Interrupt pending?
  497.         jz      isr_exit                ; No, exit
  498.  
  499. ; Acknowledge int
  500.         mov     dx,ack_int              ; get int ack reg
  501.         xor     al,al                   ; 1st write a 0
  502.         out     dx,al
  503.         jmp     $+2                     ; delay
  504.         jmp     $+2                     ; delay
  505.         in      al,dx                   ; get int type
  506.  
  507. ; Branch to correct routine     
  508.         cbw                             ; make int type a word
  509.         mov     bx,offset int_tbl       ; point to int table    
  510.         add     bx,ax                   ; add int type
  511.         sti
  512.         call    cs:word ptr [bx]        ; go do subroutine
  513.         cli
  514.  
  515. ; Reset highest int under service by 8530
  516.         mov     al,00111000b            ; reset highest int code
  517.         mov     dx,int_enable           ; select port
  518.         out     dx,al                   ; reset the int
  519.         jmp     $+2                     ; delay
  520.         
  521. isr_exit:
  522. ; Tell 8259A we're done
  523.         mov     al,EOI
  524.         out     int_ack,al
  525.  
  526.         pop     ds
  527.         pop     dx
  528.         pop     cx
  529.         pop     bx
  530.         pop     ax
  531.  
  532. ; restore stack
  533.         mov     ss,cs:word ptr old_ss
  534.         mov     sp,cs:word ptr old_sp
  535.  
  536.         sti
  537.         iret
  538.  
  539.     page
  540. ;***********************************************************
  541. ;**     Subroutine to read the modem status               **
  542. ;***********************************************************
  543. mod_stat:
  544.         mov     dx,modem_status         ; Read modem status (CHB)
  545.         xor     al,al                   ; reg 0
  546.         out     dx,al                   ; Select reg 0
  547.         jmp     $+2                     ; delay
  548.         jmp     $+2                     ; delay
  549.         in      al,dx                   ; read reg 0
  550.         mov     cl,5                    ; move bits to AH
  551.         shl     ax,cl
  552.         xor     al,al                   ; Read reg 0
  553.         mov     dx,modem_status         ; Read modem status  (CHB)
  554.         inc     dx                      ; adjust to channel A
  555.         inc     dx
  556.         out     dx,al                   ; Select reg 0
  557.         jmp     $+2                     ; delay
  558.         jmp     $+2                     ; delay
  559.         in      al,dx                   ;   into reg AL
  560.  
  561.         shl     al,1                    ; adjust to match ACS lib
  562.         shl     al,1
  563.         shl     ax,1
  564.         shl     al,1
  565.         shl     ax,1
  566.         and     ah,00011111b            ; mask unwanted bits
  567.  
  568. ; AH now contains the line signals
  569. ; ---------------------------------
  570. ; | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  571. ; ---------------------------------
  572. ; |   |   |   | RI|SCF|DSR|CTS|DCD|
  573. ; ---------------------------------
  574. ; 0=down, 1=up
  575.  
  576.         mov     cs:byte ptr m_stat,ah   ; Update current modem status
  577.  
  578. ; Check for busy handling
  579.         shr     ah,1                    ; DSR in bit 0
  580.         shr     ah,1
  581.         cmp     cs:byte ptr busy_hand,2 ; DSR busy handling?
  582.         jne     chk_4scf                ;  No, skip
  583.         mov     al,ah                   ; save AH
  584.         jmp     set_tbusy               ; go set or reset busy
  585. chk_4scf:
  586.         cmp     cs:byte ptr busy_hand,1 ; SCF busy handling?
  587.         jne     rst_sts                 ;  No, skip
  588.         shr     ah,1
  589.         mov     al,ah                   ; save AH
  590. set_tbusy:
  591.         and     al,1                    ; up = busy on
  592. ;       not     al                      ; down = busy on
  593.         mov     cs:byte ptr t_busy,al   ; set busy
  594.  
  595.  
  596. ; reset ext stat int
  597. rst_sts:
  598.         mov     al,10h                  ; reset ext sts code
  599.         mov     dx,modem_status         ; reset chan B
  600.         out     dx,al
  601.         jmp     $+2                     ; delay
  602.         mov     dx,uart_control         ; reset chan A
  603.         out     dx,al
  604.  
  605.         ret
  606.  
  607.     page
  608. ;***********************************************************
  609. ;**     Subroutine to send the next char in queue         **
  610. ;***********************************************************
  611. xmit_mt:
  612.         mov     cs:byte ptr xmit_busy,0 ; We're not busy
  613.  
  614. ; reset xmit int
  615.         mov     al,00101000b            ; code
  616.         mov     dx,uart_control
  617.         out     dx,al
  618.  
  619.         ret
  620.  
  621.     page
  622. ;***********************************************************
  623. ;**     Subroutine to receive a char and queue it         **
  624. ;***********************************************************
  625. rec_full:
  626.         mov     dx,recv_buffer          ; Get char
  627.         in      al,dx
  628.         cmp     cs:byte ptr parity_on,0 ; parity?
  629.         jz      no_par                  ;   No, don't mask off parity bit
  630.         and     al,7fh                  ;   Yes, mask off parity bit
  631. no_par:
  632. ; check for XON-XOFF busy char
  633.         cmp     cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
  634.         jne     queue_char              ;  No, skip busy handling
  635.         cmp     al,xoff                 ; Need to set busy?
  636.         jne     chk_r_xon               ;  No, skip
  637.         mov     cs:byte ptr t_busy,1    ; set busy
  638.         jmp     xit_rec_full            ; We're done
  639.  
  640. chk_r_xon:
  641.         cmp     al,xon                  ; Need to reset busy?
  642.         jne     queue_char              ;  No, skip busy handling
  643.         mov     cs:byte ptr t_busy,0    ; reset busy
  644.         jmp     xit_rec_full            ; We're done
  645.  
  646. queue_char:
  647. ; check for buffer overflow
  648.         cmp     cs:word ptr rq_len,recv_limit ; buffer full?
  649.         jb      buf_full1               ; No, skip
  650.         inc     cs:word ptr rq_tail     ; Yes, lose 1 char
  651.         and     cs:word ptr rq_tail,recv_limit
  652.         dec     cs:word ptr rq_len      ; Adjust queue length
  653. buf_full1:
  654.  
  655.         mov     bx,offset rqueue        ; Queue char
  656.         mov     dx,cs:word ptr rq_head
  657.         add     bx,dx
  658.         mov     cs:byte ptr [bx],al
  659.         inc     dx
  660.         and     dx,recv_limit           ; wrap if >= receive size
  661.         mov     cs:word ptr rq_head,dx
  662.         inc     cs:word ptr rq_len      ; Adjust queue length
  663.  
  664. ; set busy if needed
  665.         cmp     cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
  666.         jne     set_rb_done             ; No, skip
  667.         cmp     cs:word ptr rq_len,busy_len ; Need to set busy?
  668.         jb      set_rb_done             ; No, skip
  669.         mov     cs:byte ptr r_busy,1    ; set busy flag
  670.         mov     dx,cs:word ptr send_buffer ; send XOFF char
  671.         mov     al,xoff
  672.         out     dx,al
  673. set_rb_done:
  674.  
  675. xit_rec_full:
  676.         ret
  677.  
  678.     page
  679. ;***********************************************************
  680. ;**     Subroutine to send an xon char if needed          **
  681. ;***********************************************************
  682. send_xon:
  683.         cmp     cs:byte ptr busy_hand,3 ; XON-XOFF busy handling?
  684.         jne     xit_send_xon            ; No, skip
  685.         mov     dx,cs:word ptr send_buffer ; send XON char
  686.         mov     al,xon
  687.         out     dx,al
  688.  
  689. xit_send_xon:
  690.     ret
  691.  
  692.     page
  693. ;***********************************************************
  694. ;**     Subroutine to read the line status                **
  695. ;***********************************************************
  696. lin_stat:
  697.         mov     dx,uart_status
  698.         mov     al,1                    ; select reg 1
  699.         out     dx,al
  700.         jmp     $+2                     ; delay
  701.         jmp     $+2                     ; delay
  702.         in      al,dx                   ; read status
  703.         mov     cs:byte ptr l_stat,al   ; Update current line status
  704.  
  705. ; reset error
  706.         mov     al,00110000b            ; reset lin stat error code
  707.         out     dx,al
  708.  
  709.         ret
  710.  
  711.     page
  712. ;***********************************************************
  713. ;**     Subroutine to get an interrupt vector             **
  714. ;**                                                       **
  715. ;**   di = vector number                                  **
  716. ;**                                                       **
  717. ;**   Return:                                             **
  718. ;**   bx = segment                                        **
  719. ;**   dx = offset                                         **
  720. ;***********************************************************
  721. get_vector:
  722.         push    es
  723.         xor     ax,ax
  724.         mov     es,ax
  725.         shl     di,1
  726.         shl     di,1
  727.         mov     dx,es:word ptr[di]
  728.         mov     bx,es:word ptr[di+2]
  729.         pop     es
  730.         ret
  731.  
  732.     page
  733. ;***********************************************************
  734. ;**     Subroutine to set an interrupt vector             **
  735. ;**                                                       **
  736. ;**   di = vector number                                  **
  737. ;**   bx = segment                                        **
  738. ;**   dx = offset                                         **
  739. ;***********************************************************
  740. set_vector:
  741.         push    es
  742.         xor     ax,ax
  743.         mov     es,ax
  744.         shl     di,1
  745.         shl     di,1
  746.         mov     es:word ptr[di],dx
  747.         mov     es:word ptr[di+2],bx
  748.         pop     es
  749.         ret
  750.  
  751.  
  752.     page
  753. ;***********************************************************
  754. ;**  Everything past here is truncated after install      **
  755. ;***********************************************************
  756.  
  757. init    proc    near
  758.         lds     bx,cs:[ptrsav]
  759.         mov     word ptr [bx].trans,offset init ;set break address
  760.         mov     [bx].trans+2,cs
  761.  
  762. print_init:
  763.         push    cs
  764.         pop     ds
  765.         mov     dx,offset init_msg
  766.         mov     ah,9
  767.         int     21h
  768.  
  769.         jmp     exit
  770. init    endp
  771.  
  772. init_msg:
  773.         db      cr,lf,'TI PC Communications Driver v2.51'
  774.         db      ' Copyright (C) Texas Instruments 1986'
  775.         db      cr,lf,'Written by '
  776.         db      'Greg Haley'
  777.         db      cr,lf,cr,lf,'$'
  778. code    ends
  779.         end
  780.